﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Activities.Statements;
using System.Activities;
using System.Activities.Expressions;

using NUnit.Framework;

using ERPStore.Extensions;

namespace ERPStore.Tasks.Tests
{
	[TestFixture]
	public class ScheduledTaskServiceTests : ERPStore.Tests.TestBase
	{
		public ScheduledTaskServiceTests()
		{

		}

		[SetUp]
		public override void Initialize()
		{
			base.Initialize();
			var taskService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.IScheduledTaskService>();
		}

		[Test]
		public void Add_Task_Entry()
		{
			var taskEntry = new ERPStore.Models.TaskEntry();
			taskEntry.Period = ERPStore.Models.ScheduledTaskTimePeriod.Minute;
			taskEntry.Interval = 1;
			taskEntry.Name = "test";

			var taskService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Tasks.Services.ScheduledTaskService>();
			taskService.Add(taskEntry);

			Assert.IsTrue(taskService.Contains("test"));
		}

		[Test]
		public void Task_Entry_Can_Run()
		{
			var taskEntry = new ERPStore.Models.TaskEntry();
			taskEntry.Name = "test";
			taskEntry.Period = ERPStore.Models.ScheduledTaskTimePeriod.Day;
			taskEntry.Interval = 1;

			var taskService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Tasks.Services.ScheduledTaskService>();

			var canRun = taskService.CanRun(DateTime.Now, taskEntry);

			Assert.AreEqual(canRun, true);
		}

		[Test]
		public void Delayed_TaskEntry_CanotRun()
		{
			var taskEntry = new ERPStore.Models.TaskEntry();
			taskEntry.Name = "test";
			taskEntry.Period = ERPStore.Models.ScheduledTaskTimePeriod.Day;
			taskEntry.Interval = 1;
			taskEntry.DelayedStart = 100;

			var taskService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Tasks.Services.ScheduledTaskService>();

			var canRun = taskService.CanRun(DateTime.Now, taskEntry);

			Assert.AreEqual(canRun, false);
		}

		[Test]
		public void Daily_Task()
		{
			var taskName = Guid.NewGuid().ToString();
			var taskEntry = new ERPStore.Models.TaskEntry();
			Variable<int> isAssigned = new Variable<int>("Test", 0);
			taskEntry.Name = taskName;
			taskEntry.Period = ERPStore.Models.ScheduledTaskTimePeriod.Day;
			taskEntry.Interval = 1;
			taskEntry.GetActivityInstance = () =>
				{
					return new Sequence()
					{
						Variables = { isAssigned },
						Activities = {
							new Assign<int>()
							{
								To = ExpressionServices.ConvertReference<int>(ctx => isAssigned.Get(ctx)),
								Value = ExpressionServices.Convert<int>(ctx => 1)
							},
						},
					};
				};

			var taskService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Tasks.Services.ScheduledTaskService>();
			taskService.Add(taskEntry);

			var startDate = DateTime.Now;

			taskService.ProcessNextTasks();

			var task = taskService.GetList().Single(i => i.Name == taskName);
			Assert.AreEqual(task.StartedCount, 1);

			// Relance
			taskService.ProcessNextTasks();

			task = taskService.GetList().Single(i => i.Name == taskName);
			// La tache ne doit avoir été éxécuté qu'une fois
			Assert.AreEqual(task.StartedCount, 1);

			// +1 jour
			startDate = startDate.AddDays(1);
			taskService.ProcessNextTasks(startDate);

			task = taskService.GetList().Single(i => i.Name == taskName);
			// La tache ne doit avoir été éxécuté qu'une fois
			Assert.AreEqual(task.StartedCount, 2);
		}

		[Test]
		public void Task_With_Exception()
		{
			var taskEntry = new ERPStore.Models.TaskEntry();
			taskEntry.Name = "test";
			taskEntry.Period = ERPStore.Models.ScheduledTaskTimePeriod.Day;
			taskEntry.Interval = 1;
			taskEntry.GetActivityInstance = () =>
			{
				return new Sequence()
				{
					Activities = {
							new Throw()
							{
								Exception = new InArgument<Exception>((env) =>
										new Exception("test exception")
									)
							},
						},
				};
			};

			var taskService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Tasks.Services.ScheduledTaskService>();
			taskService.Add(taskEntry);

			taskService.ProcessNextTasks();

		}

		[Test]
		public void Thread_Leak()
		{
			var taskName = Guid.NewGuid().ToString();

			var taskEntry = new ERPStore.Models.TaskEntry();
			taskEntry.Name = taskName;
			taskEntry.Period = ERPStore.Models.ScheduledTaskTimePeriod.Minute;
			taskEntry.Interval = 1;
			taskEntry.WorkflowProperties.Add("TypeArgument", typeof(Dummy));
			taskEntry.GetActivityInstance = () => new Task();

			var taskService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Tasks.Services.ScheduledTaskService>();
			taskService.Add(taskEntry);

			var startDate = DateTime.Now;

			taskService.Start();

			var threadCount = System.Diagnostics.Process.GetCurrentProcess().Threads.Count;

			for (int i = 0; i < 1000; i++)
			{
				taskService.ProcessTask(taskEntry);
			}

			var afterThreadCount = System.Diagnostics.Process.GetCurrentProcess().Threads.Count;

			taskService.Stop();

			Assert.AreEqual(threadCount, afterThreadCount);
		}
	}
}
